﻿/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef SHARED_BINARY_BYTEBUFFER_H_
#define SHARED_BINARY_BYTEBUFFER_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cstddef>
#include <cstdint>
#include <vector>
#include "Shared/Global_Macros.h"
#include "Shared/Binary/ByteBufferException.h"
#include "Shared/Util/ByteConverter.h"


namespace Shared {
namespace Binary {

    class ByteBuffer
    {
    public:
        const static ::std::size_t DEFAULT_SIZE = 0x1000;   /* 默认缓存大小 */
        const static ::std::size_t MAX_SIZE = 0x100000;     /* 最大缓存大小 */

        typedef std::vector<std::uint8_t>::size_type size_type;

    public:
        ByteBuffer(void)
            : _rpos(0)
            , _wpos(0)
            , _storage()
        {
            _storage.reserve(DEFAULT_SIZE);
        }

        explicit ByteBuffer(size_type size)
            : _rpos(0)
            , _wpos(0)
        {
            _storage.reserve(size);
        }

        ByteBuffer(const ByteBuffer &buf)
            : _rpos(buf._rpos)
            , _wpos(buf._wpos)
            , _storage(buf._storage)
        {

        }

        virtual ~ByteBuffer(void)
        {

        }

        void clear()
        {
            _storage.clear();
            _rpos = _wpos = 0;
        }

        void resize(size_type nsize)
        {
            _storage.resize(nsize);
            _rpos = 0;
            _wpos = size();
        }

        size_type size(void) const
        {
            return _storage.size();
        }

        const std::uint8_t* contents(size_type index = 0) const
        {
            SHARED_ASSERT(index >= 0 && index < _storage.size());
            return &_storage[index];
        }
        std::uint8_t* contents(size_type index = 0)
        {
            SHARED_ASSERT(index >= 0 && index < _storage.size());
            return &_storage[index];
        }

        size_type rpos(void) const {
            return _rpos;
        }
        size_type wpos(void) const {
            return _wpos;
        }

        void rpos(size_type pos) {
            _rpos = pos;
        }
        void wpos(size_type pos) {
            _wpos = pos;
        }

    public:
        ///////////////////////////////////////////////////////////////////
        ByteBuffer& operator<<(std::uint8_t x)
        {
            append<std::uint8_t>(x);
            return *this;
        }
        ByteBuffer& operator<<(std::uint16_t x)
        {
            append<std::uint16_t>(x);
            return *this;
        }
        ByteBuffer& operator<<(std::uint32_t x)
        {
            append<std::uint32_t>(x);
            return *this;
        }
        ByteBuffer& operator<<(std::uint64_t x)
        {
            append<std::uint64_t>(x);
            return *this;
        }
        ByteBuffer& operator<<(float x)
        {
            append(x);
            return *this;
        }
        ByteBuffer& operator<<(const char* x)
        {
            append(x, strlen(x));
            *this << (std::uint8_t)0;
            return *this;
        }
        ByteBuffer& operator<<(const std::string& x)
        {
            append(x.c_str(), x.length());
            *this << (std::uint8_t)0;
            return *this;
        }
        ///////////////////////////////////////////////////////////////////
        ByteBuffer& operator>>(std::uint8_t& x)
        {
            x = read<std::uint8_t>();
            return *this;
        }
        ByteBuffer& operator>>(std::uint16_t& x)
        {
            x = read<std::uint16_t>();
            return *this;
        }
        ByteBuffer& operator>>(std::uint32_t& x)
        {
            x = read<std::uint32_t>();
            return *this;
        }
        ByteBuffer& operator>>(std::uint64_t& x)
        {
            x = read<std::uint64_t>();
            return *this;
        }
        ByteBuffer& operator>>(std::string& value)
        {
            value.clear();
            while (_rpos < size())
            {
                char c = read<char>();
                if (c == 0)
                { break; }
                value += c;
            }
            return *this;
        }
        ///////////////////////////////////////////////////////////////////
        std::uint8_t operator[](size_type index)
        {
            return (_storage[index]);
        }

        void append(const char* src, size_type size)
        {
            if (size == 0) {
                return;
            }

            if ((size + _wpos) > MAX_SIZE) {
                throw ByteBufferException(true, _wpos, _storage.size(), size);
            }

            if (_storage.size() < (size + _wpos)) {
                _storage.resize(size + _wpos);
            }

            memcpy(&_storage[_wpos], src, size);
            _wpos += size;
        }

        void append(const ::std::uint8_t* src, size_type size)
        {
            append((const char*)src, size);
        }

        void append(const ByteBuffer& bbuf)
        {
            append(bbuf.contents(), bbuf.size());
        }

        void read(::std::uint8_t* dest, size_type size)
        {
            if (_rpos  + size > this->size())
            { throw ByteBufferException(false, _rpos, this->size(), size); }
            memcpy(dest, &_storage[_rpos], size);
            _rpos += size;
        }

        template<typename T>
        void put(size_t pos, T& x)
        {
            Util::endianConvert(x);
            put(pos, (std::uint8_t*)&x, sizeof(T));
        }

        void put(size_type pos, std::uint8_t *ptr, std::size_t size)
        {
            if (pos + size > this->size())
            { throw ByteBufferException(true, pos, size, this->size()); }
            memcpy(&_storage[pos], ptr, size);
        }

        template <typename T> T read()
        {
            T r = read<T>(_rpos);
            _rpos += sizeof(T);
            return r;
        }

    protected:
        template <typename T> T read(size_t pos) const
        {
            if (pos + sizeof(T) > size())
            { throw ByteBufferException(false, pos, size(), sizeof(T)); }
            T val = *((T const*)&_storage[pos]);
            Util::endianConvert(val);
            return val;
        }

        template<typename T>
        void append(T x)
        {
            append((const char*)&x, sizeof(T));
        }

    protected:
        size_type                       _rpos;      /* 当前读取位置 */
        size_type                       _wpos;      /* 当前写入位置 */
        std::vector<::std::uint8_t>     _storage;   /* 存储器 */
    };

}}

#endif // SHARED_BINARY_BYTEBUFFER_H_
